// db.js的作用就是统一Model的定义：
// 统一主键，名称必须是id，类型必须是STRING(50)；
// 主键可以自己指定，也可以由框架自动生成（如果为null或undefined）；
// 所有字段默认为NOT NULL，除非显式指定；
// 统一timestamp机制，每个Model必须有createdAt、updatedAt和version，分别记录创建时间、修改时间和版本号。其中，createdAt和updatedAt以BIGINT存储时间戳，
//最大的好处是无需处理时区，排序方便。version每次修改时自增。
const { Sequelize, DataTypes, Model }  = require('sequelize');
const config = require('./config');

var sequelize = new Sequelize(config.database, config.username, config.password, {
    host: config.host,
    dialect: 'mysql',
    pool: {
        max: 5,
        min: 0,
        idle: 30000
    }
});

let defineModel=(name,attributes)=>{
	 var attrs = {};
	 for(let key in attributes){
		 let value = attributes[key];
		 if (typeof value === 'object' && value['type']) {
			 value.allowNull = value.allowNull || false;
			 attrs[key] = value;
		 } else {
			 attrs[key] = {
				 type: value,
				 allowNull: false
			 };
		 }
	 }
	attrs.id = {
	        type:  Sequelize.BIGINT(50),
	        primaryKey: true,
			autoIncrement: true,
	    };
	attrs.createdAt = {
		type: DataTypes.DATE,//Sequelize.BIGINT,
		// allowNull: false
	};
	attrs.updatedAt = {
		type:DataTypes.DATE,// Sequelize.BIGINT,
		// allowNull: false
	};
	attrs.version = {
		type: Sequelize.BIGINT,
		allowNull: false,
	};
		
	let returnTable= sequelize.define(name,attrs,{
				tableName: name, 
				timestamps: true ,//关闭Sequelize的自动添加timestamp的功能,总是自作聪明地加上所谓“自动化”的功能，但是会让人感到完全摸不着头脑。
				hooks:{
					beforeUpdate:obj=>{
						console.log("钩子函数",obj); 
						 let now = Date.now();
						  if (obj.isNewRecord) {
							 if (!obj.id) {
								 obj.id = generateId();
							 }
							 obj.createdAt = now;
							 obj.updatedAt = now;
							 obj.version = 0;
						 } else {
							 obj.updatedAt = Date.now();
							 obj.version++;
						 }
					}
				}
			});   
	 return returnTable;
}

module.exports= {
	defineModel,
	sync: async () => { 
		if (process.env.NODE_ENV !== 'production') {
			//一次同步所有模型   仅当数据库名称以 '_test' 结尾时,它才会运行.sync()
			return await sequelize.sync({ force: true });
			// User.sync() - 如果表不存在,则创建该表(如果已经存在,则不执行任何操作)
			// User.sync({ force: true, match: /_test$/ }) - 将创建表,如果表已经存在,则将其首先删除
			// User.sync({ alter: true, match: /_test$/ }) - 这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中进行必要的更改以使其与模型匹配.
		} else {
			throw new Error('Cannot sync() when NODE_ENV is set to \'production\'.');
		}
	 }
}